package cn.ipanel.bigdata.boot.date

import cn.ipanel.bigdata.utils.Util._

import org.joda.time.LocalDateTime
import org.joda.time.format.{DateTimeFormat, DateTimeFormatter}

/**
 * Author: lzz
 * Date: 2021/11/23 12:12
 */
class Time(private[this] val t: Long) extends Serializable {

  import Time._

  def time: Long = t
  def to(format: String = _yyyy_MM_dd_HH_mm_ss): String = {
    if (t > 0) new LocalDateTime(time).toString(getFormatter(format))
    else "-1"
  }
  def toYYYYMMddHHmmss: String = to(_yyyy_MM_dd_HH_mm_ss)

  def toTime: Int = strToI(to(s"${_HOUR}${_MINUTE}${_SECOND}"))
  def toDate: Int = strToI(to(s"${_YEAR}${_MONTH}${_DAY}"))
  def toSimpleMonth: Int = strToI(to("yyMM"))
  def toSimpleDate: Int = strToI(to("yyMMdd"))
  def toSimpleHour: Long = strToL(to("yyMMddHH"))
  def toSimpleMinute: Long = strToL(to("yyMMddHHmm"))
  def toFullHour: Long = strToL(to("yyyyMMddHH"))
  def toYear: Int = strToI(to(_YEAR))
  def toYearMonth: Int = strToI(to(s"${_YEAR}${_MONTH}"))
  def toYearQuarter: Int = strToI(s"${to(s"${_YEAR}")}$toQuarter")
  def toQuarter: Int = toMonth match {
    case Date.JANUARY | Date.FEBRUARY | Date.MARCH      => Date.Q1
    case Date.APRIL | Date.MAY | Date.JUNE       => Date.Q2
    case Date.JULY | Date.AUGUST | Date.SEPTEMBER  => Date.Q3
    case Date.OCTOBER | Date.NOVEMBER | Date.DECEMBER   => Date.Q4
    case _ => -1
  }
  def toMonth: Int = strToI(to(_MONTH))
  def toDayWeek: Int = strToI(to(_DAY_WEEK))
  def toDay: Int = strToI(to(_DAY))
  def toHour: Int = strToI(to(_HOUR))
  def toDayHour: Int = strToI(to(s"${_YEAR}${_MONTH}${_DAY}${_HOUR}"))
  def toMinute: Int = strToI(to(_MINUTE))
  def toDayMinute: Int = strToI(to(s"${_YEAR}${_MONTH}${_DAY}${_HOUR}${_MINUTE}"))
  def toSecond: Int = strToI(to(_SECOND))

  def diffToNow: Long = System.currentTimeMillis() - t
  def diffToNowS: Int = (diffToNow / 1000).toInt
  def diffToNowM: Int = diffToNowS / 60

  def asYear: Year = Year(t)
  def asMonth: Month = Month(t)
  def asWeek: Week = Week(t)
  def asDay: Day = Day(t)
  def asQuarter: Quarter = Quarter(t)
  def asHour: Hour = Hour(t)
  def asMinute: Minute = Minute(t)

  override def toString: String = {
    s"Time[$toYYYYMMddHHmmss]" + "@" + Integer.toHexString(hashCode)
  }
  override def equals(obj: Any): Boolean = {
    if (obj != null && obj.isInstanceOf[Time] && obj.asInstanceOf[Time].time == time) true else false
  }
}

object Time {

  final val SECOND: Long = 1000
  final val MINUTE: Long = 60 * SECOND

  final val _YEAR = "yyyy"
  final val _MONTH = "MM"
  final val _DAY = "dd"
  final val _DAY_WEEK = "e"
  final val _HOUR = "HH"
  final val _MINUTE = "mm"
  final val _SECOND = "ss"

  final val _yyyyMMdd  = s"${_YEAR}${_MONTH}${_DAY}"
  final val _HHmmss = s"${_HOUR}${_MINUTE}${_SECOND}"
  final val _HHmm = s"${_HOUR}${_MINUTE}"
  final val _HH_mm_ss = s"${_HOUR}:${_MINUTE}:${_SECOND}"
  final val _yyyy_MM_dd = s"${_YEAR}-${_MONTH}-${_DAY}"
  final val _yyyy_MM_dd_HH_mm_ss = s"${_yyyy_MM_dd} ${_HH_mm_ss}"
  final val _yyyyMMddHHmmss = s"${_yyyyMMdd}${_HHmmss}"
  final val _yyyyMMddHHmm = s"${_yyyyMMdd}${_HHmm}"
  final val _yyyyMMddHH = s"${_yyyyMMdd}${_HOUR}"

  private[date] def getFormatter(format: String): DateTimeFormatter = DateTimeFormat.forPattern(format)

  def apply(time: String, format: String): Time = apply(LocalDateTime.parse(time, getFormatter(format)).toDateTime.getMillis)
  def apply(yyyyMMdd: String): Time = apply(yyyyMMdd, _yyyyMMdd)
  def apply(t: Long): Time = new Time(t)

  def now: Time = Time(System.currentTimeMillis())
  def millis(dateTime: String): Long = Time(dateTime, _yyyy_MM_dd_HH_mm_ss).time

  final lazy val strTimeToMin = (sTime: String) => {
    if (nonNull(sTime)) {
      try {
        val time = Time(sTime, Time._yyyy_MM_dd_HH_mm_ss)
        time.toDayMinute
      } catch {
        case _: Exception => 0
      }
    } else 0
  }

  final lazy val strTimeToHour = (sTime: String) => {
    if (nonNull(sTime)) {
      try {
        val time = Time(sTime, Time._yyyy_MM_dd_HH_mm_ss)
        time.toDayHour
      } catch {
        case _: Exception => 0
      }
    } else 0
  }
}